package ws

import (
	"encoding/json"
	"fmt"

	"github.com/gin-gonic/gin"
	"github.com/golang/protobuf/proto"
	"github.com/gorilla/websocket"
)

// Request .
type Request struct {
	conn     *Connection
	Seq      uint16 // 序列号
	Route    uint16 // 路由ID
	ByteData []byte
}

func (r *Request) GetIP() string {
	return r.conn.wsConn.RemoteAddr().String()
}

// GetConn .
func (r *Request) GetConn() *Connection {
	return r.conn
}

// GetMsgID .
func (r *Request) GetMsgID() uint16 {
	return r.Seq
}

func (r *Request) Send(msg proto.Message) error {
	protoData, err := proto.Marshal(msg)
	if err != nil {
		return err
	}
	// 构造响应包：seq(2 bytes big-endian) + route(2 bytes big-endian) + protobuf body
	header := make([]byte, 4)
	header[0] = byte(r.Seq >> 8)
	header[1] = byte(r.Seq & 0xFF)
	header[2] = byte(r.Route >> 8)
	header[3] = byte(r.Route & 0xFF)

	sendData := append(header, protoData...)

	return r.conn.Send(sendData)
}

func (r *Request) Pong() error {
	return r.conn.wsConn.WriteMessage(websocket.TextMessage, []byte(""))
}

// SendJSON .
func (r *Request) SendJSON(msg interface{}) (err error) {
	return r.conn.SendJSON(gin.H{"status": 200, "id": r.Route, "data": msg})
}

// SendErr .
func (r *Request) SendErr(msg interface{}) (err error) {
	return r.conn.SendJSON(gin.H{"status": 400, "id": r.Route, "data": msg})
}

// SetMsg .
func (r *Request) SetMsg(data []byte) {
	// 期望最小长度为 4（seq 2 bytes + route 2 bytes）
	if len(data) < 4 {
		r.Pong()
		return
	}

	// 前端编码：seq(2 bytes big-endian) + route(2 bytes big-endian) + protobuf body
	r.Seq = uint16(data[0])<<8 | uint16(data[1])
	r.Route = uint16(data[2])<<8 | uint16(data[3])

	// 剩余为 protobuf body（可能包含结尾填充 0）
	body := data[4:]
	// 如果最后一字节是 0（前端有时会附加），去掉它
	if len(body) > 0 && body[len(body)-1] == 0 {
		body = body[:len(body)-1]
	}
	r.ByteData = body
	// fmt.Printf("SetMsg: 提取到的 Seq: %d, Route(ID): %d, BodyLen: %d\n", r.Seq, r.Route, len(r.ByteData))
}

// BindProto 将 ByteData 反序列化到提供的 protobuf 消息对象中
func (r *Request) BindProto(msg proto.Message) error {
	if len(r.ByteData) == 0 {
		return fmt.Errorf("empty proto body")
	}
	return proto.Unmarshal(r.ByteData, msg)
}

// Bind .
func (r *Request) Bind(v interface{}) error {
	return json.Unmarshal(r.ByteData, v)
}

// Message .
type Message struct {
	ID uint16 `json:"id"`
	// dataLen uint32
	Data map[string]interface{} `json:"data"`
}

// NewMsg .
func NewMsg(id uint16, data map[string]interface{}) *Message {
	return &Message{
		ID:   id,
		Data: data,
	}
}

// GetMsgLen .
// func (m *Message) GetMsgLen() uint32 {
// 	return m.dataLen
// }
